﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(FaceRigControl))]
public class FaceRigControlEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var o = (FaceRigControl)target;
        base.OnInspectorGUI();
        o.Update();
        //if (GUILayout.Button("SetMin"))
        //{
        //    o.SetMin();
        //}
        //if (GUILayout.Button("SetMax"))
        //{
        //    o.SetMax();
        //}
        if (GUILayout.Button("SetMirror"))
        {
            o.SetMirror();
        }
        if (GUILayout.Button("SetOrigin"))
        {
            o.SetOrigin();
        }
    }
}
#endif
public class FaceRigControl : MonoBehaviour
{
    public float cheekHorizonValue;
    public Vector3 cheekHorizonMOM;
    public RelativeMove cheekHorizonRM;
    public float eyeDistanceValue;
    public Vector3 eyeDistanceMOM;
    public RelativeMove eyeDistanceRM;
    public float eyeHorizonValue;
    public Vector3 eyeHorizonMOM;
    public RelativeMove eyeHorizonRM;
    public float eyeVerticalValue;
    public Vector3 eyeVerticalMOM;
    public RelativeMove eyeVerticalRM;

    public float eyeHlHorizonValue_L;
    public Vector3 eyeHlHorizonMOM_L;
    public RelativeMove eyeHlHorizonRM_L;
    public float eyeHlHorizonValue_R;
    public Vector3 eyeHlHorizonMOM_R;
    public RelativeMove eyeHlHorizonRM_R;

    public float eyeHl2HorizonValue_L;
    public Vector3 eyeHl2HorizonMOM_L;
    public RelativeMove eyeHl2HorizonRM_L;
    public float eyeHl2HorizonValue_R;
    public Vector3 eyeHl2HorizonMOM_R;
    public RelativeMove eyeHl2HorizonRM_R;

    public float jawVerticalValue;
    public Vector3 jawVerticalMOM;
    public RelativeMove jawVerticalRM;

    public float eyeBrowBoneHorizonValue;
    public Vector3 eyeBrowBoneHorizonMOM;
    public RelativeMove eyeBrowBoneHorizonRM;
    public float eyeBrowBoneVerticalValue;
    public Vector3 eyeBrowBoneVerticalMOM;
    public RelativeMove eyeBrowBoneVerticalRM;

    //public float eyeLashAngleValue;
    public Vector3 eyeLashAngleMOM;
    //public RelativeRotater eyeLashAngleRR;

    public float eyeLidVerticalValue;
    public Vector3 eyeLidVerticalMOM;
    public RelativeMove eyeLidVerticalRM;

    public float eyeLidAngleValue;
    public Vector3 eyeLidAngleMOM;
    public RelativeRotater eyeLidAngleRR;

    public float eyeWidthValue;
    public Vector3 eyeWidthMOM;
    public float eyeLengthValue;
    public Vector3 eyeLengthMOM;
    public Transform eyeScaleT;
    public Transform eyeScaleTM;

    public float eyePupilWidthValue;
    public Vector3 eyePupilWidthMOM;
    public float eyePupilNormalPosValue;
    public Vector3 eyePupilNormalPosMOM;
    public float eyePupilLengthValue;
    public Vector3 eyePupilLengthMOM;
    public Transform eyePupilScaleT;
    public Transform eyePupilScaleTM;

    public Transform eyeLashScaleT;
    public Transform eyeLashScaleTM;

    public LabelSlider CheekHorizonSlider;
    public LabelSlider EyeDistSlider;
    public LabelSlider EyeHorizonSlider;
    public LabelSlider EyeVerticalSlider;
    public LabelSlider EyeHlHorizonSlider_L;
    public LabelSlider EyeHlHorizonSlider_R;
    public LabelSlider EyeHl2HorizonSlider_L;
    public LabelSlider EyeHl2HorizonSlider_R;
    public LabelSlider JawVerticalSlider;
    public LabelSlider EyeBrowBoneHorizonSlider;
    public LabelSlider EyeBrowBoneVerticalSlider;

    public LabelSlider EyeLashAngleSlider;
    public LabelSlider EyeLidVerticalSlider;
    public LabelSlider EyeLidAngleSlider;
    public LabelSlider EyeWidthSlider;
    public LabelSlider EyeLengthSlider;
    public LabelSlider EyePupilNormalPosSlider;
    public LabelSlider EyePupilWidthSlider;
    public LabelSlider EyePupilLengthSlider;

    public bool clampMOM;
    public float pupilMulty;

    public bool solveOn;
    private bool busy;
    private string data;

    public float eyeLidVertical2HLWeight = 0.28f;
    public float eyeLidAngle2HLWeight = 0.001f;
    public float eyeLidVertical2HL2Weight = 0.1f;
    public AnimationCurve lashCurve;
    public AnimationCurve lashScaleZCurve;
    public float osHLVOrigin = -0.1f;
    public SkinnedMeshRenderer eyeLashSMR;
    public SkinnedMeshRenderer eyeHLSMR;
    public SkinnedMeshRenderer eyeHL2SMR;
    public Vector2 eyeLashScaleYMM;
    public Vector2 eyeLashScaleZMM;
    public Material matIgnore;
    public SliderMgr sdMgr;
    internal void SetOrigin()
    {
        foreach (var rm in GetComponentsInChildren<RelativeMove>())
        {
            rm.SetOrigin();
        }
    }
    public void SetMirror()
    {
        foreach (var rm in GetComponentsInChildren<RelativeMove>())
        {
            rm.mirror = transform.Search(rm.name.Substring(0, rm.name.Length - 2) + ".r");
        }
        foreach (var rm in GetComponentsInChildren<RelativeRotater>())
        {
            rm.mirror = transform.Search(rm.name.Substring(0, rm.name.Length - 2) + ".r");
        }
        eyeScaleTM = FindMirror(eyeScaleT);
        eyePupilScaleTM = FindMirror(eyePupilScaleT);
        eyeLashScaleTM = FindMirror(eyeLashScaleT);
    }
    Transform FindMirror(Transform t)
    {
        return transform.Search(t.name.Substring(0, t.name.Length - 2) + ".r");
    }
    //internal void SetMax()
    //{
    //    cheekHorizonMOM.z = cheekHorizonRM.relativePos.y;
    //    eyeDistanceMOM.z = eyeDistanceRM.relativePos.y;
    //    eyeHorizonMOM.z = eyeHorizonRM.relativePos.x;
    //    eyeHlHorizonMOM.z = eyeHlHorizonRM.relativePos.x;
    //}
    //internal void SetMin()
    //{
    //    cheekHorizonMOM.x = cheekHorizonRM.relativePos.y;
    //    eyeDistanceMOM.x = eyeDistanceRM.relativePos.y;
    //    eyeHorizonMOM.x = eyeHorizonRM.relativePos.x;
    //}
    void Start()
    {
        solveOn = true;
        clampMOM = true;
    }
    private void OnApplicationQuit()
    {
        solveOn = false;
    }
    public void Update()
    {
        if (!solveOn) return;
        if (clampMOM)
        {
            cheekHorizonValue = Mathf.Clamp(cheekHorizonValue, cheekHorizonMOM.x, cheekHorizonMOM.z);
            eyeDistanceValue = Mathf.Clamp(eyeDistanceValue, eyeDistanceMOM.x, eyeDistanceMOM.z);
            eyeHorizonValue = Mathf.Clamp(eyeHorizonValue, eyeHorizonMOM.x, eyeHorizonMOM.z);
            eyeVerticalValue = Mathf.Clamp(eyeVerticalValue, eyeVerticalMOM.x, eyeVerticalMOM.z);
            eyeHlHorizonValue_L = Mathf.Clamp(eyeHlHorizonValue_L, eyeHlHorizonMOM_L.x, eyeHlHorizonMOM_L.z);
            eyeHlHorizonValue_R = Mathf.Clamp(eyeHlHorizonValue_R, eyeHlHorizonMOM_R.x, eyeHlHorizonMOM_R.z);
            eyeHl2HorizonValue_L = Mathf.Clamp(eyeHl2HorizonValue_L, eyeHl2HorizonMOM_L.x, eyeHl2HorizonMOM_L.z);
            eyeHl2HorizonValue_R = Mathf.Clamp(eyeHl2HorizonValue_R, eyeHl2HorizonMOM_R.x, eyeHl2HorizonMOM_R.z);
            jawVerticalValue = Mathf.Clamp(jawVerticalValue, jawVerticalMOM.x, jawVerticalMOM.z);
            eyeBrowBoneHorizonValue = Mathf.Clamp(eyeBrowBoneHorizonValue, eyeBrowBoneHorizonMOM.x, eyeBrowBoneHorizonMOM.z);
            eyeBrowBoneVerticalValue = Mathf.Clamp(eyeBrowBoneVerticalValue, eyeBrowBoneVerticalMOM.x, eyeBrowBoneVerticalMOM.z);
            //eyeLashAngleValue = Mathf.Clamp(eyeLashAngleValue, eyeLashAngleMOM.x, eyeLashAngleMOM.z);
            eyeLidVerticalValue = Mathf.Clamp(eyeLidVerticalValue, eyeLidVerticalMOM.x, eyeLidVerticalMOM.z);
            eyeLidAngleValue = Mathf.Clamp(eyeLidAngleValue, eyeLidAngleMOM.x, eyeLidAngleMOM.z);
            eyeWidthValue = Mathf.Clamp(eyeWidthValue, eyeWidthMOM.x, eyeWidthMOM.z);
            eyeLengthValue = Mathf.Clamp(eyeLengthValue, eyeLengthMOM.x, eyeLengthMOM.z);
            eyePupilNormalPosValue = Mathf.Clamp(eyePupilNormalPosValue, eyePupilNormalPosMOM.x, eyePupilNormalPosMOM.z);
            eyePupilWidthValue = Mathf.Clamp(eyePupilWidthValue, eyePupilWidthMOM.x, eyePupilWidthMOM.z);
            eyePupilLengthValue = Mathf.Clamp(eyePupilLengthValue, eyePupilLengthMOM.x, eyePupilLengthMOM.z);
        }
        cheekHorizonRM.relativePos = Vector3.up * cheekHorizonValue;
        eyeDistanceRM.relativePos = Vector3.up * eyeDistanceValue;
        eyeHorizonRM.relativePos = -Vector3.right * eyeHorizonValue + Vector3.up * eyeVerticalValue;
        eyeVerticalRM.relativePos = -Vector3.right * eyeHorizonValue + Vector3.up * eyeVerticalValue;
        var os = Vector3.up * osHLVOrigin;
        var t = (1f - EyeLidVerticalSlider.nt);
        os -= Vector3.up * t * eyeLidVertical2HLWeight;
        os -= Vector3.up * eyeLidAngleValue * eyeLidAngle2HLWeight;
        eyeHlHorizonRM_L.relativePos = -Vector3.right * eyeHlHorizonValue_L + os;
        eyeHlHorizonRM_R.relativePos = -Vector3.right * eyeHlHorizonValue_R + os;
        os = -Vector3.up * t * eyeLidVertical2HL2Weight;
        eyeHl2HorizonRM_L.relativePos = -Vector3.right * eyeHl2HorizonValue_L + os;
        eyeHl2HorizonRM_R.relativePos = -Vector3.right * eyeHl2HorizonValue_R + os;
        jawVerticalRM.relativePos = Vector3.up * jawVerticalValue;
        eyeBrowBoneHorizonRM.relativePos = Vector3.right * eyeBrowBoneVerticalValue + Vector3.up * eyeBrowBoneHorizonValue;
        eyeBrowBoneVerticalRM.relativePos = Vector3.right * eyeBrowBoneVerticalValue + Vector3.up * eyeBrowBoneHorizonValue;
        //eyeLashAngleRR.relativeAngleX = Mathf.Clamp(eyeLashAngleValue, eyeLashAngleMOM.x, eyeLashAngleMOM.z);

        var render = eyeHLSMR.GetComponent<Renderer>();
        render.enabled = sdMgr.eyeHlToggle.isOn && eyeLidVerticalValue > -1;
        render = eyeHL2SMR.GetComponent<Renderer>();
        render.enabled = sdMgr.eyeHl2Toggle.isOn && eyeLidVerticalValue > -1;

        eyeLidVerticalRM.relativePos = Vector3.right * eyeLidVerticalValue;
        eyeLidAngleRR.relativeAngleZ = Mathf.Clamp(eyeLidAngleValue, eyeLidAngleMOM.x, eyeLidAngleMOM.z);
        eyeScaleTM.localScale = eyeScaleT.localScale = new Vector3(
            Mathf.Clamp(eyeWidthValue, eyeWidthMOM.x, eyeWidthMOM.z),
            Mathf.Clamp(eyeLengthValue, eyeLengthMOM.x, eyeLengthMOM.z), 1f);
        eyePupilScaleTM.localScale = eyePupilScaleT.localScale = new Vector3(
            Mathf.Clamp(eyePupilWidthValue, eyePupilWidthMOM.x, eyePupilWidthMOM.z),
            Mathf.Clamp(eyePupilLengthValue, eyePupilLengthMOM.x, eyePupilLengthMOM.z), 1f);
        t = (1 - EyeLashAngleSlider.nt);
        var scl = new Vector3(1, Mathf.Lerp(eyeLashScaleYMM.x, eyeLashScaleYMM.y, t),
            1 + lashScaleZCurve.Evaluate(EyeLashAngleSlider.nt));
        var m = eyeLashSMR.sharedMaterial;
        int cullMode = scl.y < 0 ? front : back;
        m.SetInt("_CullMode", cullMode);
        eyeLashSMR.sharedMaterials = new Material[] { m, scl.y > 0 ? m : matIgnore };
        eyeLashScaleTM.localScale = eyeLashScaleT.localScale = scl;
        eyePupilScaleT.localPosition = eyePupilScaleT.localPosition.SetZ(0.02878895f + eyePupilNormalPosValue);
        eyePupilScaleTM.localPosition = eyePupilScaleTM.localPosition.SetZ(0.02878895f + eyePupilNormalPosValue);
    }
    public void ResetFace()
    {
        Awake();
        sdMgr.emitter.ClearUnits();
        sdMgr.ResetSettings();
    }
    public void Awake()
    {
        CheekHorizonSlider.Init(cheekHorizonMOM, OnCheekHorizonChanged);
        EyeDistSlider.Init(eyeDistanceMOM, OnEyeDistChanged);
        EyeHorizonSlider.Init(eyeHorizonMOM, OnEyeHorizonChanged);
        EyeVerticalSlider.Init(eyeVerticalMOM, OnEyeVerticalChanged);
        EyeHlHorizonSlider_L.Init(eyeHlHorizonMOM_L, OnEyeHlHorizonChanged_L);
        EyeHlHorizonSlider_R.Init(eyeHlHorizonMOM_R, OnEyeHlHorizonChanged_R);
        EyeHl2HorizonSlider_L.Init(eyeHl2HorizonMOM_L, OnEyeHl2HorizonChanged_L);
        EyeHl2HorizonSlider_R.Init(eyeHl2HorizonMOM_R, OnEyeHl2HorizonChanged_R);
        JawVerticalSlider.Init(jawVerticalMOM, OnJawVerticalChanged);
        EyeBrowBoneHorizonSlider.Init(eyeBrowBoneHorizonMOM, OnEyeBrowBoneHorizonChanged);
        EyeBrowBoneVerticalSlider.Init(eyeBrowBoneVerticalMOM, OnEyeBrowBoneVerticalChanged);
        EyeLashAngleSlider.Init(eyeLashAngleMOM, null);// OnEyeLashAngleChanged);
        EyeLidAngleSlider.Init(eyeLidAngleMOM, OnEyeLidAngleChanged);
        EyeLidVerticalSlider.Init(eyeLidVerticalMOM, OnEyeLidVerticalChanged);
        EyeWidthSlider.Init(eyeWidthMOM, OnEyeWidthChanged);
        EyeLengthSlider.Init(eyeLengthMOM, OnEyeLengthChanged);
        EyePupilNormalPosSlider.Init(eyePupilNormalPosMOM, OnEyePupilNormalPosChanged);
        EyePupilWidthSlider.Init(eyePupilWidthMOM, OnEyePupilWidthChanged);
        EyePupilLengthSlider.Init(eyePupilLengthMOM, OnEyePupilLengthChanged);
    }
    string Read(int count)
    {
        var sec = data.Substring(0, count);
        data = data.Substring(count);
        return sec;
    }
    public float String6ToFloat2_3
    {
        get
        {
            string s = Read(6);
            int i;
            int.TryParse(s, out i);
            float v = i * 0.001f;
            return v;
        }
    }
    public string Float2_3ToString6(float v)
    {
        v *= 1000;
        int i = (int)v;
        var format = "00000"; // 整数2位 + 小数3位 + 符号1位
        var s = i.ToString(format);
        if (i >= 0) s = "+" + s;
        if (s.Length != 6) { Debug.LogError(s); throw new Exception("len diff"); }
        return s;
    }
    public bool String1ToBool
    {
        get
        {
            string s = Read(1); // no sign
            int i;
            int.TryParse(s, out i);
            bool v = i != 0;
            return v;
        }
    }
    public string BoolToString1(bool v)
    {
        int i = v ? 1 : 0;
        return i.ToString();
    }
    public string GenerateCode()
    {
        string str = "";
        str += BoolToString1(sdMgr.eyeBrowBoneToggle.isOn);
        str += BoolToString1(sdMgr.eyeFoldToggle.isOn);
        str += BoolToString1(sdMgr.eyeLashToggle.isOn);
        str += BoolToString1(sdMgr.eyeHlToggle.isOn);
        str += BoolToString1(sdMgr.eyeHl2Toggle.isOn);
        str += Float2_3ToString6(sdMgr.hairStencilOutAplhaSlider.value);

        str += Float2_3ToString6(cheekHorizonValue);
        str += Float2_3ToString6(eyeBrowBoneVerticalValue);
        str += Float2_3ToString6(eyeBrowBoneHorizonValue);
        str += Float2_3ToString6(eyeVerticalValue);
        str += Float2_3ToString6(eyeHorizonValue);
        str += Float2_3ToString6(eyeWidthValue);
        str += Float2_3ToString6(eyeLengthValue);
        str += Float2_3ToString6(eyePupilNormalPosValue);
        str += Float2_3ToString6(eyePupilWidthValue);
        str += Float2_3ToString6(eyePupilLengthValue);
        str += Float2_3ToString6(EyeLashAngleSlider.nt);
        str += Float2_3ToString6(eyeLidVerticalValue);
        str += Float2_3ToString6(eyeLidAngleValue);
        str += Float2_3ToString6(eyeHlHorizonValue_L);
        str += Float2_3ToString6(eyeHlHorizonValue_R);
        str += Float2_3ToString6(eyeHl2HorizonValue_L);
        str += Float2_3ToString6(eyeHl2HorizonValue_R);
        str += Float2_3ToString6(eyeDistanceValue);
        str += Float2_3ToString6(jawVerticalValue);
        return str;
    }
    public void ReadCode(string v)
    {
        if (busy) return;
        busy = true;
        data = v;

        sdMgr.eyeBrowBoneToggle.isOn = String1ToBool;
        sdMgr.eyeFoldToggle.isOn = String1ToBool;
        sdMgr.eyeLashToggle.isOn = String1ToBool;
        sdMgr.eyeHlToggle.isOn = String1ToBool;
        sdMgr.eyeHl2Toggle.isOn = String1ToBool;
        sdMgr.hairStencilOutAplhaSlider.value = String6ToFloat2_3;

        cheekHorizonValue = String6ToFloat2_3;
        eyeBrowBoneVerticalValue = String6ToFloat2_3;
        eyeBrowBoneHorizonValue = String6ToFloat2_3;
        eyeVerticalValue = String6ToFloat2_3;
        eyeHorizonValue = String6ToFloat2_3;
        eyeWidthValue = String6ToFloat2_3;
        eyeLengthValue = String6ToFloat2_3;
        eyePupilNormalPosValue = String6ToFloat2_3;
        eyePupilWidthValue = String6ToFloat2_3;
        eyePupilLengthValue = String6ToFloat2_3;
        EyeLidVerticalSlider.value = String6ToFloat2_3;
        EyeLashAngleSlider.nt = String6ToFloat2_3;
        EyeLidAngleSlider.value = String6ToFloat2_3;
        eyeHlHorizonValue_L = String6ToFloat2_3;
        eyeHlHorizonValue_R = String6ToFloat2_3;
        eyeHl2HorizonValue_L = String6ToFloat2_3;
        eyeHl2HorizonValue_R = String6ToFloat2_3;
        eyeDistanceValue = String6ToFloat2_3;
        jawVerticalValue = String6ToFloat2_3;

        busy = false;
    }
    const int off = 0;
    const int front = 1;
    const int back = 2;
    //private void OnEyeLashAngleChanged(float v)
    //{
    //    eyeLashAngleValue = v;
    //}
    private void OnEyeLidVerticalChanged(float v)
    {
        eyeLidVerticalValue = v;
        var t = eyeLidVerticalValue - eyeLidVerticalMOM.x;
        t = t == 0 ? 0 : t / (eyeLidVerticalMOM.z - eyeLidVerticalMOM.x);
        EyeLidAngleSlider.value = Mathf.Lerp(eyeLidAngleMOM.x, eyeLidAngleMOM.z, 1f - t);
        EyeLashAngleSlider.value = Mathf.Lerp(eyeLashAngleMOM.x, eyeLashAngleMOM.z, lashCurve.Evaluate(1f - t));
    }
    private void OnEyeLidAngleChanged(float v)
    {
        eyeLidAngleValue = v;
    }
    private void OnEyeWidthChanged(float v)
    {
        eyeWidthValue = v;
    }
    private void OnEyeLengthChanged(float v)
    {
        eyeLengthValue = v;
    }
    void OnEyePupilNormalPosChanged(float v)
    {
        eyePupilNormalPosValue = v;
    }
    private void OnEyePupilWidthChanged(float v)
    {
        eyePupilWidthValue = v;
    }
    private void OnEyePupilLengthChanged(float v)
    {
        eyePupilLengthValue = v;
    }
    private void OnEyeBrowBoneVerticalChanged(float v)
    {
        eyeBrowBoneVerticalValue = v;
    }
    private void OnEyeBrowBoneHorizonChanged(float v)
    {
        eyeBrowBoneHorizonValue = v;
    }
    private void OnJawVerticalChanged(float v)
    {
        jawVerticalValue = v;
    }
    private void OnCheekHorizonChanged(float v)
    {
        cheekHorizonValue = v;
    }
    private void OnEyeDistChanged(float v)
    {
        eyeDistanceValue = v;
    }
    private void OnEyeHorizonChanged(float v)
    {
        eyeHorizonValue = v;
    }
    private void OnEyeVerticalChanged(float v)
    {
        eyeVerticalValue = v;
    }
    private void OnEyeHlHorizonChanged_L(float v)
    {
        eyeHlHorizonValue_L = v;
    }
    private void OnEyeHl2HorizonChanged_L(float v)
    {
        eyeHl2HorizonValue_L = v;
    }
    private void OnEyeHlHorizonChanged_R(float v)
    {
        eyeHlHorizonValue_R = v;
    }
    private void OnEyeHl2HorizonChanged_R(float v)
    {
        eyeHl2HorizonValue_R = v;
    }
}
